package com.hframe.log;

import com.hframe.thread.ThreadPool;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.Date;

/**
 * 操作日志管理器
 * Created by heqian on 17-9-13.
 */
public class UseLogManage {
    private static Logger log = Logger.getLogger(UseLogManage.class);
    private static UseLogManage mInterface = null;
    private volatile ArrayList<UseLog> mListLogs = new ArrayList<>();
    private Class<? extends OnSaveUseLog> mUseLog = null;
    private Object mLock = new Object();
    private Object mLockSave = new Object();
    private int mMaxCount = 10;
    private boolean mAsync = true;

    /**
     * 获得管理接口
     *
     * @return
     */
    public static UseLogManage get() {
        if (null == mInterface)
            mInterface = new UseLogManage();
        return mInterface;
    }

    /**
     * 获得最大缓存数量
     *
     * @return
     */
    public int getMaxCount() {
        return this.mMaxCount;
    }

    /**
     * 设置最大缓存数量
     *
     * @param maxCount
     */
    public void setMaxCount(int maxCount) {
        this.mMaxCount = maxCount;
    }

    /**
     * 设置操作日志保存接口
     *
     * @param mUseLog
     */
    public void setSaveUseLog(Class<? extends OnSaveUseLog> mUseLog) {
        synchronized (mLockSave) {
            this.mUseLog = mUseLog;
        }
    }

    /**
     * 保存操作日志
     */
    public void flush() {
        flush(mAsync);
    }
    
    private void flush(boolean async) {
        OnSaveUseLog saveUseLog;
        synchronized (mLockSave) {
            try {
                if (null == mUseLog)
                    return;

                saveUseLog = mUseLog.newInstance();
            } catch (Exception e) {
                log.error(e.toString(), e);
                return;
            }
        }

        ArrayList<UseLog> temp;
        synchronized (mLock) {
            temp = mListLogs;
            mListLogs = new ArrayList<>();
        }

        if (async) {
            ThreadPool.get().execute(new Runnable() {
                public OnSaveUseLog mUseLog;
                public ArrayList<UseLog> mTemp;

                public Runnable init(ArrayList<UseLog> temp, OnSaveUseLog useLog) {
                    this.mTemp = temp;
                    this.mUseLog = useLog;
                    return this;
                }

                @Override
                public void run() {
                    save(this.mTemp, this.mUseLog);
                }
            }.init(temp, saveUseLog));

        } else {
            save(temp, saveUseLog);
        }
    }

    /**
     *  退出时一定要调用些此方法
     */
    public void close(){
        flush(false);
    }
    
    
    private void save(ArrayList<UseLog> temp, OnSaveUseLog useLog) {
        useLog.onStart(temp);
        for (UseLog item : temp) {
            useLog.onSave(item);
        }
        useLog.onFinish(temp);
    }

    /**
     * 添加操作日志
     *
     * @param useLog
     */
    public void addUseLog(UseLog useLog) {
        useLog.setDateTime(new Date());
        synchronized (mLock) {
            mListLogs.add(useLog);
        }
        if (mListLogs.size() >= mMaxCount)
            flush();
    }

    /**
     *保存日志接口
     */
    public interface OnSaveUseLog {

        /**
         * 保存日志之前，一般用于打开数据库或文件
         * @param useLogs
         */
        void onStart(ArrayList<UseLog> useLogs);

        /**
         * 开始保存
         * @param useLog
         */
        void onSave(UseLog useLog);

        /**
         * 保存日志之后， 一般用于关闭数据库或文件
         * @param useLogs
         */
        void onFinish(ArrayList<UseLog> useLogs);
    }
}
